package com.cloudea.learn.layer;

import com.cloudea.learn.Tensor;

/**
 * 对Tensor的一些操作符，没有参数
 * @author cloudea
 * @date 2021/12/29
 */
public class Operator {

    /**
     * 普通的矩阵向量乘法
     * @param matrix 矩阵   (a, b)
     * @param vector 向量   (b,)
     * @return 向量  (a, )
     */
    public static Tensor gemv(Tensor matrix, Tensor vector){
        int[] matrixShape = matrix.getShape();
        int[] vectorShape = vector.getShape();
        int a = matrixShape[0], b = matrixShape[1];
        Tensor v = new Tensor(a);
        for (int i = 0; i < a; i++){
            double sum = 0;
            for (int j = 0; j < b; j++){
                sum += matrix.get(i, j) * vector.get(j);
            }
            v.set(sum, i);
        }
        return v;
    }

    /**
     * 向量乘法
     * @param vector1 向量1 (a, )
     * @param vector2 向量2 (a, )
     * @return 相乘的结果 (a, )
     */
    public static Tensor vectorMul(Tensor vector1, Tensor vector2){
        int a = vector1.getShape()[0];
        Tensor v = new Tensor(a);
        for (int i = 0; i < a; i++){
            v.set(vector1.get(i) * vector2.get(i), i);
        }
        return v;
    }

    /**
     * 向量加法
     * @param vector1 向量1 (a, )
     * @param vector2 向量2 (a, )
     * @return 相加的结果 (a, )
     */
    public static Tensor vectorAdd(Tensor vector1, Tensor vector2){
        int a = vector1.getShape()[0];
        Tensor v = new Tensor(a);
        for (int i = 0; i < a; i++){
            v.set(vector1.get(i) + vector2.get(i), i);
        }
        return v;
    }

    /**
     * 做sigmoid运算
     * @param tensor  维度任意的一个tensor
     * @return 结果
     */
    public static Tensor sigmoid(Tensor tensor){
        tensor = tensor.copy();
        tensor.map(new Tensor.Lambda() {
            @Override
            public double map(double x) {
                return 1 / (1 + Math.exp(- x));
            }
        });
        return tensor;
    }

    /**
     * 做tanh运算
     * @param tensor  维度任意的一个tensor
     * @return 结果
     */
    public static Tensor tanh(Tensor tensor){
        tensor = tensor.copy();
        tensor.map(new Tensor.Lambda() {
            @Override
            public double map(double x) {
                //return 2*(1 / (1 + Math.exp(- 2*x))) -1;
                return Math.tanh(x);
            }
        });
        return tensor;
    }

    /**
     * 做relu运算
     * @param tensor  维度任意的一个tensor
     * @return 结果
     */
    public static Tensor relu(Tensor tensor){
        tensor = tensor.copy();
        tensor.map(new Tensor.Lambda() {
            @Override
            public double map(double x) {
                return Math.max(0, x);
            }
        });
        return tensor;
    }

    /**
     * 做leakyrelu运算
     * @param tensor  维度任意的一个tensor
     * @return 结果
     */
    public static Tensor leakyRelu(Tensor tensor){
        tensor = tensor.copy();
        tensor.map(new Tensor.Lambda() {
            @Override
            public double map(double x) {
                return Math.max(0.01*x, x);
            }
        });
        return tensor;
    }

    /**
     * 做leakyrelu运算
     * @param tensor  维度任意的一个tensor
     * @return 结果
     */
    public static Tensor elu(Tensor tensor, double alpha){
        tensor = tensor.copy();
        tensor.map(new Tensor.Lambda() {
            @Override
            public double map(double x) {
                return x > 0 ? x : (alpha * Math.exp(x) - 1);
            }
        });
        return tensor;
    }

}
